/*
 * NetworkManager.java
 *
 * Created on 28 de Fevereiro de 2005, 20:12
 */

package net.onmotion.network;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.StreamConnection;

import net.onmotion.util.Log;

/**
 * 
 * @author sestevao
 */
public class NetworkManager {

  public static NetworkManager networkManager = null;

  public static int error = 0;

  public static int NO_ERROR = 0;

  public static int IO_ERROR = 1;

  public static int SECURITY_ERROR = 2;

  public static byte[] sendReceive(String url, NetworkData dataToSend) {

    error = NO_ERROR;

    if (networkManager == null) {
      networkManager = new NetworkManager();
    }
    networkManager.setUrl(url);

    if (!networkManager.isAvailable()) {
      networkManager.start();
    }

    byte[] data = null;

    data = networkManager.sendReceive(dataToSend);

    return data;
  }

  StreamConnection sc = null;

  DataInputStream dis = null;

  DataOutputStream dos = null;

  String url = null;

  public static int HTTP = 0;

  public static int SOCKET = 1;

  public int mode = 0;

  /** Creates a new instance of NetworkManager */
  public NetworkManager() {

  }

  public void setUrl(String aUrl) {
    url = aUrl;
    if (url.startsWith("http")) {
      mode = HTTP;
    } else {
      mode = SOCKET;
    }
  }

  public boolean isAvailable() {
    if (mode == SOCKET) {
      return (sc != null);
    } else {
      return true;
    }
  }

  public void start() {
    try {
      if (mode == SOCKET) {
        if (sc == null) {
          sc = (StreamConnection) Connector.open(url, Connector.READ_WRITE);
          dos = sc.openDataOutputStream();
          dis = sc.openDataInputStream();
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      stop();
    }
  }

  public void stop() {
    try {
      if (dos != null) {
        dos.close();
        dos = null;
      }
      if (dis != null) {
        dis.close();
        dis = null;
      }
      if (sc != null) {
        sc.close();
        sc = null;
      }
    } catch (Exception ex) {
      dos = null;
      dis = null;
      sc = null;
    }
  }

  public byte[] sendReceive(NetworkData dataToSend) {
    if (mode == SOCKET) {
      return socketConnection(dataToSend);
    } else {
      return httpConnection(url, dataToSend);
    }

  }

  private synchronized byte[] socketConnection(NetworkData dataToSend) {
    byte[] data = null;
    try {
      // Prepare Connection
      if (sc == null) {
        sc = (StreamConnection) Connector.open(url, Connector.READ_WRITE);
        dos = sc.openDataOutputStream();
        dis = sc.openDataInputStream();
      }

      // Write Data
      dos.writeInt(dataToSend.getLength());
      dos.write(dataToSend.getData());
      dos.flush();

      // Read Data
      int len = dis.readInt();
      data = new byte[len];
      dis.readFully(data);

    } catch (IOException e) {
      error = IO_ERROR;
      Log.log("Network error:", e);
      stop();
      data = null;
    } catch (SecurityException e) {
      error = SECURITY_ERROR;
      Log.log("Network security error:", e);
      stop();
      data = null;
    }

    return data;
  }

  private byte[] httpConnection(String url, NetworkData dataToSend) {
    HttpConnection hc = null;
    InputStream in = null;
    byte[] data = null;
    String requestMethod = dataToSend.method;
    try {
      int rc = 0;
      // String rm = null;
      boolean redirect = true;
      while (redirect) {
        // Prepare Connection
        hc = (HttpConnection) Connector.open(url + dataToSend.getUrlExtra(),
            Connector.READ_WRITE);
        hc.setRequestMethod(requestMethod);
        hc.setRequestProperty("User-Agent",
            "Profile/MIDP-1.0 Configuration/CLDC-1.0");
        // hc.setRequestProperty("Content-type",
        // "application/octet-stream" );
        // hc.setRequestProperty("Accept", "application/octet-stream" );
        // hc.setRequestProperty("Connection", "close" );
        if (requestMethod == HttpConnection.POST) {
          Log.log("Post");
          hc.setRequestProperty("Content-Type", dataToSend.contentType);
          hc.setRequestProperty("Content-Length", Integer.toString(dataToSend
              .getLength()));
          Log.log("Content-Length:" + dataToSend.getLength());
          // Write Data
          OutputStream os = hc.openOutputStream();
          os.write(dataToSend.getData());
          os.flush();
          os.close();
        }

        rc = hc.getResponseCode();
        // rm = hc.getResponseMessage();

        switch (rc) {
        case (HttpConnection.HTTP_SEE_OTHER):
        case (HttpConnection.HTTP_MOVED_PERM):
        case (HttpConnection.HTTP_MOVED_TEMP):
        case (HttpConnection.HTTP_TEMP_REDIRECT):

          url = hc.getHeaderField("Location");
          if ((url != null) && url.startsWith("/*")) {
            StringBuffer b1 = new StringBuffer();
            b1.append("http://");
            b1.append(hc.getHost());
            b1.append(':');
            b1.append(hc.getPort());
            b1.append(url);
            url = b1.toString();
          }

          hc.close();
          break;

        default:
          redirect = false;
          break;
        }

        requestMethod = HttpConnection.POST;
        if (rc == HttpConnection.HTTP_MOVED_TEMP
            || rc == HttpConnection.HTTP_SEE_OTHER) {
          // requestMethod = HttpConnection.GET;
        }
      }
      if (rc == HttpConnection.HTTP_OK) {
        // Read Data
        long len = (long) hc.getLength();
        in = hc.openInputStream();

        if (len != -1) {
          int total = 0;
          data = new byte[(int) len];

          while (total < len) {
            total += in.read(data, total, (int) len - total);
          }
        } else {
          ByteArrayOutputStream tmp = new ByteArrayOutputStream();
          int ch;

          while ((ch = in.read()) != -1) {
            tmp.write(ch);
          }

          data = tmp.toByteArray();
        }
        in.close();
      }
      hc.close();

    } catch (IOException e) {
      error = IO_ERROR;
      Log.log("Network error:", e);
      data = null;
    } catch (SecurityException e) {
      error = SECURITY_ERROR;
      Log.log("Network security error:", e);
      data = null;
    }

    return data;
  }
}
